import unittest
from functools import reduce
from Conference import \
    Session\
    , Talk\
    , SessionEndTime\
    , TraceNode\
    , Conference\
    , TraceNodeMaker


def talk_with_lines(lines):
    talks = []
    for line in lines:
        line = line
        talk = Talk(line, tag=len(talks))
        if talk.verifyContent():
            talks.append(talk)
    return talks


def example_test_data() -> list:
    talks = []
    file = open("testdata.txt")
    for line in file:
        line = line.strip('\n')
        talk = Talk(line, tag=len(talks))
        if talk.verifyContent():
            talks.append(talk)
    file.close()
    return talks


def some_test_data() ->list:
    data = """
    1 10min
    2 20min
    3 30min
    4 40min
    5 50min
    6 60min
    7 70min
    """
    return talk_with_lines(lines=data.split('\n'))


def test_data() ->list:
    data = """
    1 5min
    2 5min
    3 10min
    4 2min
    5 3min
    """
    return talk_with_lines(lines=data.split('\n'))


class SessionTest(unittest.TestCase):
    def test(self):
        session1 = Session(9, SessionEndTime(20))
        session1.printTalks(some_test_data())
        print('')
        session1.printTalks(test_data())
        self.assertEqual(True, True)


class ConferenceTest(unittest.TestCase):
    def test(self):
        m_session = Session(9, SessionEndTime(10))
        af_session = Session(13, SessionEndTime(14))
        con1 = Conference(m_session, af_session, example_test_data())
        con1.print()

        m_session = Session(9, SessionEndTime(12))
        af_session = Session(13, SessionEndTime(16, 17))
        con1 = Conference(m_session, af_session, example_test_data())
        con1.printTraceNodesCount()
        self.assertEqual(True, True)


class TraceNodeMakerTest(unittest.TestCase):
    def test(self):
        maker1 = TraceNodeMaker(15, 15, test_data())
        self.assertEqual(maker1.totalSchemeCount(), 4, '方案总数')
        self.assertEqual(len(maker1.traceNodes), 4, '路线总数')
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

        maker1 = TraceNodeMaker(15, 10, test_data())
        self.assertEqual(maker1.schemeCountForTime(maker1.minDuration), 4, '%d方案总数' % maker1.minDuration)
        self.assertEqual(maker1.schemeCountForTime(maker1.maxDuration), 4, '%d方案总数' % maker1.maxDuration)
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

        maker1 = TraceNodeMaker(120, 120, some_test_data())
        self.assertEqual(maker1.totalSchemeCount(), 8, '方案总数')
        self.assertEqual(len(maker1.traceNodes), 8, '路线总数')
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

        maker1 = TraceNodeMaker(120, 60, some_test_data())
        self.assertEqual(maker1.schemeCountForTime(maker1.minDuration), 4, '%d方案总数' % maker1.minDuration)
        self.assertEqual(maker1.schemeCountForTime(maker1.maxDuration), 8, '%d方案总数' % maker1.maxDuration)
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

        maker1 = TraceNodeMaker(180, 180, example_test_data())
        self.assertEqual(maker1.totalSchemeCount(), 1467, '方案总数')
        self.assertEqual(len(maker1.traceNodes), 1467, '路线总数')
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

        maker1 = TraceNodeMaker(240, 180, example_test_data())
        self.assertEqual(maker1.schemeCountForTime(maker1.minDuration), 1467, '%d方案总数' % maker1.minDuration)
        self.assertEqual(maker1.schemeCountForTime(maker1.maxDuration), 4980, '%d方案总数' % maker1.maxDuration)
        self.assertEqual(len(maker1.traceNodes), 25544, '路线总数')
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

        maker1 = TraceNodeMaker(240, 180, example_test_data())
        self.assertEqual(maker1.schemeCountForTime(maker1.minDuration), 1467, '%d方案总数' % maker1.minDuration)
        self.assertEqual(maker1.schemeCountForTime(maker1.maxDuration), 4980, '%d方案总数' % maker1.maxDuration)
        self.assertEqual(len(maker1.traceNodes), 25544, '路线总数')
        self.assertEqual(len(maker1.traceNodes), maker1.totalSchemeCount(), '方案总数等于路线总数')
        self.verify_maker_nodes(maker1)

    # TODO 测试每条会议路线是否合法 - 所有演讲的时间相加等于本次会议时间或者在会议时间范围内
    def verify_maker_nodes(self, maker):
        for node in maker.traceNodes:
            self.verify_node(node, maker)

    def verify_node(self, trace_node: TraceNode, maker: TraceNodeMaker):
        talks = trace_node.talks
        durations = map(lambda x: x.duration, talks)
        total_duration = reduce(lambda x, y: x + y, durations)
        if maker.minDuration == maker.maxDuration:
            self.assertEqual(total_duration, maker.maxDuration, '固定时长会议: 单条路线时长应该等于会议总时长')
        else:
            self.assertGreaterEqual(total_duration, maker.minDuration,
                                    '范围时长会议: 单条路线时长应该大于等于会议最小时长')
            self.assertLessEqual(total_duration, maker.maxDuration, '范围时长会议: 单条路线时长应该小于等于会议最大时长')


class TalkTest(unittest.TestCase):
    def test(self):
        talk1 = Talk('content 10min')
        self.assertTrue(talk1.verifyContent(), '合法')
        self.assertEqual(talk1.duration, 10, '演讲时长')

        talk2 = Talk('wrong content')
        self.assertFalse(talk2.verifyContent(), '不合法')

        talk3 = Talk('content lightning')
        self.assertEqual(talk3.duration, 5, '演讲时长')


class SessionEndTimeTest(unittest.TestCase):

    def test(self):
        time1 = SessionEndTime(9, 9)
        self.assertEqual(time1.marginTime, 0)
        self.assertEqual(time1.earliestHour, 9)
        self.assertEqual(time1.latestHour, 9)

        time2 = SessionEndTime(9, 12)
        self.assertEqual(time2.marginTime, 180)
        self.assertEqual(time2.earliestHour, 9)
        self.assertEqual(time2.latestHour, 12)


if __name__ == '__main__':
    unittest.main(verbosity=2)
